package com.example.xcService.pojo.task;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.example.entity.*;
import com.example.mapper.ProductCardMapper;
import com.example.pojo.enums.OrderEnum;
import com.example.pojo.enums.PollingEnum;
import com.example.pojo.enums.ProductCardEnum;
import com.example.pojo.rabbitmq.OrderFanoutProduce;
import com.example.pojo.rabbitmq.RefundFanoutProduce;
import com.example.pojo.response.CardData;
import com.example.service.*;
import com.example.service.impl.ThoroughfareServiceImpl;
import com.example.pojo.util.MybatisBatchUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
public class OrderTransactional {
    @Autowired
    IThoroughfareChannelService thoroughfareChannelService;

    @Autowired
    IChannelService channelService;

    @Autowired
    IChannelProductService channelProductService;

    @Autowired
    IApiInfoService apiInfoService;

    @Autowired
    IAgentOrderService agentOrderService;


    @Autowired
    IChannelOrderService channelOrderService;

    @Autowired
    ThoroughfareServiceImpl thoroughfareService;

    @Autowired
    IOrderPollingService pollingService;

    @Autowired
    IAgentService agentService;

    @Autowired
    IProductCardService cardService;

    @Autowired
    IAccountLogService logService;

    @Autowired
    MybatisBatchUtils mybatisBatchUtils;

    @Autowired
    RefundFanoutProduce refundFanoutProduce;

    @Autowired
    OrderFanoutProduce submitProduce;

    @Transactional(isolation = Isolation.READ_COMMITTED ,rollbackFor = Exception.class)
    public  void  UpdateCard(AgentOrder order, List<ProductCard> cardList){
        List<CardData> dataList = new ArrayList<>();
        if (!mybatisBatchUtils.batchUpdateOrInsert(cardList, ProductCardMapper.class,
                (item, uiConfigDetailMapper) -> uiConfigDetailMapper.updateById(item))){
            LambdaQueryWrapper<ProductCard> query = new LambdaQueryWrapper<>();
            query.eq(ProductCard::getProductId, order.getProductId());
            query.eq(ProductCard::getCardStatus, ProductCardEnum.Effective);
            query.last("ORDER BY RAND() limit " + order.getBuyNum());

            cardList = cardService.list(query);
            if (cardList.size() <= 0) {
                order.setErrMsg("库存不足");
                order.setOrderStatus(OrderEnum.ERROR);
                agentOrderService.updateById(order);
                return;
            }
            for (ProductCard card : cardList) {
                CardData cardData = new CardData();
                cardData.setUrl(card.getCardUrl());
                cardData.setType(card.getType());
                cardData.setCode(card.getCardKey());
                cardData.setKey(card.getCardCode());
                cardData.setEffstart(card.getGmtEffective());
                cardData.setEffend(card.getGmtExpire());
                dataList.add(cardData);
                card.setAccount(order.getAccount());
                card.setCardStatus(ProductCardEnum.Used);
                card.setGmtUse(LocalDateTime.now());
                card.setOrderId(order.getId());
            }
            order.setOrderInfo(JSONObject.toJSONStringWithDateFormat(dataList, "yyyy-MM-dd", SerializerFeature.WriteMapNullValue));
            if (!mybatisBatchUtils.batchUpdateOrInsert(cardList, ProductCardMapper.class,
                    (item, uiConfigDetailMapper) -> uiConfigDetailMapper.updateById(item))){
                throw new  RuntimeException("卡密乐观锁修改失败");
            }
        }


        LambdaUpdateWrapper<AgentOrder> updateWrapper=new LambdaUpdateWrapper<>();
        updateWrapper.eq(AgentOrder::getId,order.getId());
        updateWrapper.eq(AgentOrder::getOrderStatus,OrderEnum.UNDERWAY);
        if(!agentOrderService.update(order,updateWrapper)){
            AgentOrder dbOrder = agentOrderService.getById(order.getId());
            if (OrderEnum.SUCCESS.equals(dbOrder.getOrderStatus()) || OrderEnum.FAILED.equals(dbOrder.getOrderStatus()) ){
                return;
            }
            dbOrder.setOrderInfo(order.getOrderInfo());
            dbOrder.setErrMsg(order.getErrMsg());
            dbOrder.setOrderStatus(order.getOrderStatus());
            if (!agentOrderService.updateById(dbOrder)){
                throw new  RuntimeException("乐观锁修改失败");
            }
        }
    }

    @Transactional(isolation = Isolation.READ_COMMITTED ,rollbackFor = Exception.class)
    public  void  saveOrder(AgentOrder order, OrderPolling polling){
        LambdaUpdateWrapper<AgentOrder> updateWrapper=new LambdaUpdateWrapper<>();
        updateWrapper.eq(AgentOrder::getId,order.getId());
        updateWrapper.and(wrappers->wrappers.eq(AgentOrder::getOrderStatus,OrderEnum.ERROR).or().eq(AgentOrder::getOrderStatus,OrderEnum.WAIT).or().eq(AgentOrder::getOrderStatus,OrderEnum.UNDERWAY));
        if(!agentOrderService.update(order,updateWrapper)){
            AgentOrder dbOrder = agentOrderService.getById(order.getId());
            if (OrderEnum.SUCCESS.equals(dbOrder.getOrderStatus()) || OrderEnum.FAILED.equals(dbOrder.getOrderStatus()) || OrderEnum.IN_PROCESS.equals(dbOrder.getOrderStatus()) ){
                return;
            }
            dbOrder.setOrderInfo(order.getOrderInfo());
            dbOrder.setErrMsg(order.getErrMsg());
            dbOrder.setOrderStatus(order.getOrderStatus());
            if (!agentOrderService.updateById(dbOrder)){
                throw new  RuntimeException("乐观锁修改失败");
            }
        }
        LambdaQueryWrapper<OrderPolling> query=new LambdaQueryWrapper();
        query.eq(OrderPolling::getPollingId,polling.getPollingId());
        OrderPolling dbPolling= pollingService.getOne(query);

        if (dbPolling!=null){
            if (dbPolling.getOrderStatus()!= PollingEnum.ERROR && dbPolling.getOrderStatus()!=PollingEnum.SubmitERROR){
                throw new  RuntimeException("乐观锁修改失败");
            }
            dbPolling.setErrMsg(polling.getErrMsg());
            dbPolling.setOrderStatus(polling.getOrderStatus());
            pollingService.updateById(dbPolling);
        }else {
            pollingService.save(polling);
        }
    }


    @Transactional(isolation = Isolation.READ_COMMITTED ,rollbackFor = Exception.class)
    public  void  saveOrder(AgentOrder order,OrderPolling polling,ChannelOrder channelOrder){
        LambdaUpdateWrapper<AgentOrder> updateWrapper=new LambdaUpdateWrapper<>();
        updateWrapper.eq(AgentOrder::getId,order.getId());
        updateWrapper.and(wrappers->wrappers.eq(AgentOrder::getOrderStatus,OrderEnum.ERROR).or().eq(AgentOrder::getOrderStatus,OrderEnum.WAIT).or().eq(AgentOrder::getOrderStatus,OrderEnum.UNDERWAY));
        if(!agentOrderService.update(order,updateWrapper)){
            AgentOrder dbOrder = agentOrderService.getById(order.getId());
            if (OrderEnum.SUCCESS.equals(dbOrder.getOrderStatus()) || OrderEnum.FAILED.equals(dbOrder.getOrderStatus()) || OrderEnum.IN_PROCESS.equals(dbOrder.getOrderStatus()) ){
                return;
            }
            dbOrder.setOrderInfo(order.getOrderInfo());
            dbOrder.setErrMsg(order.getErrMsg());
            dbOrder.setOrderStatus(order.getOrderStatus());
            if (!agentOrderService.updateById(dbOrder)){
                throw new  RuntimeException("乐观锁修改失败");
            }
        }
        LambdaQueryWrapper<OrderPolling> query=new LambdaQueryWrapper();
        query.eq(OrderPolling::getPollingId,polling.getPollingId());
        OrderPolling dbPolling= pollingService.getOne(query);

        if (dbPolling!=null){
            if (dbPolling.getOrderStatus()!= PollingEnum.ERROR && dbPolling.getOrderStatus()!=PollingEnum.SubmitERROR){
                throw new  RuntimeException("乐观锁修改失败");
            }
            dbPolling.setErrMsg(polling.getErrMsg());
            dbPolling.setOrderStatus(polling.getOrderStatus());
            pollingService.updateById(dbPolling);
        }else {
            pollingService.save(polling);
        }
        if (channelOrder.getId()!=null){
            channelOrderService.updateById(channelOrder);
        }else {
            channelOrderService.save(channelOrder);
        }
    }



    @Transactional(isolation = Isolation.READ_COMMITTED ,rollbackFor = Exception.class)
    public  void  updateOrder(AgentOrder order,OrderPolling polling){
        LambdaUpdateWrapper<AgentOrder> updateWrapper=new LambdaUpdateWrapper<>();
        updateWrapper.eq(AgentOrder::getId,order.getId());
        updateWrapper.and(wrappers->wrappers.ne(AgentOrder::getOrderStatus,OrderEnum.SUCCESS).or().ne(AgentOrder::getOrderStatus,OrderEnum.FAILED));
        if(!agentOrderService.update(order,updateWrapper)){
            AgentOrder dbOrder = agentOrderService.getById(order.getId());
            if (OrderEnum.SUCCESS.equals(dbOrder.getOrderStatus()) || OrderEnum.FAILED.equals(dbOrder.getOrderStatus()) ){
                return;
            }
            dbOrder.setOrderInfo(order.getOrderInfo());
            dbOrder.setErrMsg(order.getErrMsg());
            dbOrder.setOrderStatus(order.getOrderStatus());
            if (!agentOrderService.updateById(dbOrder)){
                throw new  RuntimeException("乐观锁修改失败");
            }
        }
        pollingService.updateById(polling);

    }

    @Transactional(isolation = Isolation.READ_COMMITTED ,rollbackFor = Exception.class)
    public  void  updateOrder(AgentOrder order,OrderPolling polling,ChannelOrder channelOrder){
        LambdaUpdateWrapper<AgentOrder> updateWrapper=new LambdaUpdateWrapper<>();
        updateWrapper.eq(AgentOrder::getId,order.getId());
        updateWrapper.and(wrappers->wrappers.ne(AgentOrder::getOrderStatus,OrderEnum.SUCCESS).or().ne(AgentOrder::getOrderStatus,OrderEnum.FAILED));
        if(!agentOrderService.update(order,updateWrapper)){
            AgentOrder dbOrder = agentOrderService.getById(order.getId());
            if (OrderEnum.SUCCESS.equals(dbOrder.getOrderStatus()) || OrderEnum.FAILED.equals(dbOrder.getOrderStatus()) ){
                return;
            }
            dbOrder.setOrderInfo(order.getOrderInfo());
            dbOrder.setErrMsg(order.getErrMsg());
            dbOrder.setOrderStatus(order.getOrderStatus());
            if (!agentOrderService.updateById(dbOrder)){
                throw new  RuntimeException("乐观锁修改失败");
            }
        }
        pollingService.updateById(polling);
        if (channelOrder.getId()!=null){
            channelOrderService.updateById(channelOrder);
        }else {
            channelOrderService.save(channelOrder);
        }
    }


    @Transactional(isolation = Isolation.READ_COMMITTED ,rollbackFor = Exception.class)
    public  void  updateOrder(AgentOrder order){
        if(!agentOrderService.updateById(order)){
            AgentOrder dbOrder = agentOrderService.getById(order.getId());
            if (OrderEnum.SUCCESS.equals(dbOrder.getOrderStatus()) || OrderEnum.FAILED.equals(dbOrder.getOrderStatus()) ){
                return;
            }
            dbOrder.setErrMsg(order.getErrMsg());
            dbOrder.setOrderStatus(order.getOrderStatus());
            if (!agentOrderService.updateById(dbOrder)){
                throw new  RuntimeException("乐观锁修改失败");
            }
        }
    }

    @Transactional(isolation = Isolation.READ_COMMITTED ,rollbackFor = Exception.class)
    public  Boolean getAgentOrder(Integer id,Integer version){
        Boolean result=true;
        LambdaQueryWrapper<AgentOrder> query=new LambdaQueryWrapper<>();
        query.eq(AgentOrder::getVersion,version);
        query.eq(AgentOrder::getId,id);
        query.and(wrappers->wrappers.eq(AgentOrder::getOrderStatus,OrderEnum.ERROR).or().eq(AgentOrder::getOrderStatus,OrderEnum.WAIT).or().eq(AgentOrder::getOrderStatus,OrderEnum.UNDERWAY));
        AgentOrder order=agentOrderService.getOne(query);
        if (order==null){
            AgentOrder dbOrder=agentOrderService.getById(id);
            if (OrderEnum.SUCCESS.equals(dbOrder.getOrderStatus()) || OrderEnum.FAILED.equals(dbOrder.getOrderStatus()) ){
                result=false;
            }else {
                result=true;
            }

        }
        return  result;
    }
}
